package org.jeecg.chase.common.supper.query;

import org.jeecg.chase.common.base.annotation.Process;
import org.jeecg.chase.common.base.annotation.Processes;
import org.jeecg.chase.common.base.annotation.QueryConfig;
import org.jeecg.chase.common.supper.process.CommonProcess;
import org.jeecg.chase.common.supper.process.CommonProcessBuilder;

import java.util.*;


/**
 * @author leikai
 * @version 1.0
 * @description:
 * @date 2021/08/04/0004 17:34
 */
public class ListQueryContainer {

    /**
     * 查询前对query对象的处理
     */
    public static String BEFORE_QUERY_ADVICE = "beforeQueryAdvice";

    /**
     * 查询后，对查询结果的处理
     */
    public static String AFTER_QUERY_ADVICE = "afterQueryAdvice";

    /**
     * query预处理map
     */
    private static final HashMap<String, List<CommonProcess>> queryBeforeProcessMap = new HashMap<String, List<CommonProcess>>();

    /**
     * 各个query的共享预处理
     */
    private static final List<CommonProcess> shareQueryBeforeProcessList = new ArrayList<CommonProcess>();

    /**
     * 对结果的后置处理
     */
    private static final HashMap<String, List<CommonProcess>> resultAfterProcessMap = new HashMap<String, List<CommonProcess>>();

    /**
     * 承接查询结果的Bo
     */
    private static final HashMap<String, Class<?>> resultClassMap = new HashMap<String, Class<?>>();


    public static List<CommonProcess> getQueryBeforeProcessList(String modelId) {
        List<CommonProcess> processList = queryBeforeProcessMap.get(modelId);
        if (null == processList) {
            processList = new ArrayList<CommonProcess>();
        }
        List<CommonProcess> resultProcessList = new ArrayList<CommonProcess>();
        resultProcessList.addAll(shareQueryBeforeProcessList);
        resultProcessList.addAll(processList);
        return resultProcessList;
    }

    public static void addQueryBeforeProcess(String modelId, CommonProcess commonProcess) {
        List<CommonProcess> processList = queryBeforeProcessMap.get(modelId);
        if (null == processList) {
            processList = new ArrayList<CommonProcess>();
            ListQueryContainer.setQueryBeforeProcessList(modelId, processList);
        }
        processList.add(commonProcess);
    }

    public static void clearQueryBeforeProcess(String modelId) {
        queryBeforeProcessMap.put(modelId, null);
    }

    public static void clearResultAfterProcess(String modelId) {
        resultAfterProcessMap.put(modelId, null);
    }

    public static void addResultAfterProcess(String modelId, CommonProcess commonProcess) {
        List<CommonProcess> processList = getResultAfterProcessList(modelId);
        processList.add(commonProcess);
        ListQueryContainer.setResultAfterProcessList(modelId, processList);
    }

    public static void setQueryBeforeProcessList(String modelId, List<CommonProcess> processList) {
        queryBeforeProcessMap.put(modelId, processList);
    }

    public static void setResultAfterProcessList(String modelId, List<CommonProcess> processList) {
        resultAfterProcessMap.put(modelId, processList);
    }

    public static List<CommonProcess> getResultAfterProcessList(String modelId) {
        List<CommonProcess> processList = resultAfterProcessMap.get(modelId);
        if (null == processList) {
            processList = new ArrayList<CommonProcess>();
        }
        return processList;
    }

    public static Class<?> getBoClass(Class<?> queryClass) {
        return resultClassMap.get(queryClass);
    }

    public static void processQuery(Class<?> queryClass) {
        createQueryBeforeProcess(queryClass);
        createResultAfterProcess(queryClass);
        createBoClass(queryClass);
    }

    private static List<CommonProcess> createQueryBeforeProcess(Class<?> queryClass) {

        List<CommonProcess> allProcessList = queryBeforeProcessMap.get(queryClass.getName());
        if (null == allProcessList) {

            //当前类上的处理
            List<CommonProcess> processList = getCommonProcessList(queryClass);

            //父类上的处理
            List<CommonProcess> parentProcessList = new ArrayList<CommonProcess>();
            Class<?> parentClass = queryClass.getSuperclass();
            if (null != parentClass) {
                parentProcessList = queryBeforeProcessMap.get(parentClass.getName());
            }

            allProcessList = mergeProcess(processList, parentProcessList);

            queryBeforeProcessMap.put(queryClass.getName(), allProcessList);

            return allProcessList;
        }
        return allProcessList;
    }

    private static List<CommonProcess> mergeProcess(List<CommonProcess> processList, List<CommonProcess> parentProcessList) {

        List<CommonProcess> allQueryPreProcess = new ArrayList<CommonProcess>();

        if (null != parentProcessList) {
            allQueryPreProcess.addAll(parentProcessList);
        }

        if (null != processList) {
            allQueryPreProcess.addAll(processList);
        }

        return allQueryPreProcess;
    }

    private static Map<String, CommonProcess> createProcessMap(List<CommonProcess> processList) {
        Map<String, CommonProcess> processMap = new HashMap<String, CommonProcess>();
        for (CommonProcess process : processList) {
            String key = createKey(process);
            processMap.put(key, process);
        }
        return processMap;
    }

    private static String createKey(CommonProcess process) {
        String service = process.getService();
        String methodName = process.getMethod();
        String key = service + "." + methodName;
        return key;
    }

    private static List<CommonProcess> getCommonProcessList(Class<?> queryClass) {
        List<CommonProcess> commonProcessList = new ArrayList<CommonProcess>();
        QueryConfig queryConfig = (QueryConfig) queryClass.getAnnotation(QueryConfig.class);
        if (null != queryConfig) {
            List<Process> processList = new ArrayList<Process>();
            Process[] processes1 = queryConfig.queryBeforeProcess();
            Process[] processes2 = queryConfig.queryPreProcess();
            processList.addAll(Arrays.asList(processes1));
            processList.addAll(Arrays.asList(processes2));

            for (Process process : processList) {
                CommonProcess commonProcess = CommonProcessBuilder.changeToCommonProcess(process);
                commonProcessList.add(commonProcess);
            }
        }
        return commonProcessList;
    }

    private static void createResultAfterProcess(Class<?> queryClass) {
        QueryConfig queryConfig = (QueryConfig) queryClass.getAnnotation(QueryConfig.class);
        if (null != queryConfig) {
            Process[] resultAfterProcessArray = queryConfig.resultAfterProcess();
            if (null == resultAfterProcessArray || resultAfterProcessArray.length == 0) {
                Class<?> resultClass = queryConfig.resultClass();
                Processes processes = (Processes) resultClass.getAnnotation(Processes.class);
                if (null != processes) {
                    resultAfterProcessArray = processes.value();
                }
            }
            List<CommonProcess> commonProcessList = CommonProcessBuilder.changeToCommonProcessList(resultAfterProcessArray);
            resultAfterProcessMap.put(queryClass.getName(), commonProcessList);
        }
    }
    
    private static void createBoClass(Class<?> queryClass) {
        QueryConfig queryConfig = (QueryConfig) queryClass.getAnnotation(QueryConfig.class);
        if (null != queryConfig) {
            Class<?> resultClass = queryConfig.resultClass();
            resultClassMap.put(queryClass.getName(), resultClass);
        }
    }

    public static void addShareQueryBeforeProcessList(List<CommonProcess> processList) {
        shareQueryBeforeProcessList.addAll(processList);
    }
}
